home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / wave_a.c < prev    next >
Text File  |  1997-01-16  |  5KB  |  199 lines

  1. /* 
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     wave_audio.c
  21.  
  22.     Functions to output RIFF WAVE format data to a file or stdout.
  23.  
  24. */
  25.  
  26. #ifdef __EMX__
  27. #include <stdlib.h>
  28. #endif
  29.  
  30. #ifdef __WIN32__
  31. #include <stdlib.h>
  32. #include <io.h>
  33. #include <string.h>
  34. #else
  35. #include <unistd.h>
  36. #endif
  37. #include <fcntl.h>
  38. #include <errno.h>
  39.  
  40. #ifdef __FreeBSD__
  41. #include <stdio.h>
  42. #endif
  43.  
  44. #include "config.h"
  45. #include "output.h"
  46. #include "controls.h"
  47.  
  48. #ifdef __WIN32__
  49. #define OPEN_MODE O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
  50. #else
  51. #define OPEN_MODE O_WRONLY | O_CREAT | O_TRUNC
  52. #endif
  53.  
  54. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  55. static void close_output(void);
  56. static void output_data(int32 *buf, int32 count);
  57. static void flush_output(void);
  58. static void purge_output(void);
  59.  
  60. /* export the playback mode */
  61.  
  62. #define dpm wave_play_mode
  63.  
  64. PlayMode dpm = {
  65.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  66.   -1,
  67.   {0,0,0,0,0},
  68.   "RIFF WAVE file", 'w',
  69.   "output.wav",
  70.   open_output,
  71.   close_output,
  72.   output_data,
  73.   flush_output,
  74.   purge_output  
  75. };
  76.  
  77. /*************************************************************************/
  78.  
  79. static char *orig_RIFFheader=
  80.   "RIFF" "\377\377\377\377" 
  81.   "WAVE" "fmt " "\020\000\000\000" "\001\000"
  82.   /* 22: channels */ "\001\000" 
  83.   /* 24: frequency */ "xxxx" 
  84.   /* 28: bytes/second */ "xxxx" 
  85.   /* 32: bytes/sample */ "\004\000" 
  86.   /* 34: bits/sample */ "\020\000"
  87.   "data" "\377\377\377\377"
  88. ;
  89.  
  90. /* Count the number of bytes output so the header can be fixed when
  91.    closing the file */
  92. static int32 bytes_output;
  93.  
  94. /* We only support 16-bit signed and 8-bit unsigned data -- WAVEs have
  95.    to be supported because TiMidity is a "MIDI-to-WAVE converter"...
  96.  
  97.    uLaw WAVEs might be useful and not too hard to implement. I just
  98.    don't know what should go in the "fmt " block. */
  99.  
  100. static int open_output(void)
  101. {
  102.   char RIFFheader[44];
  103.   int t;
  104.  
  105.   dpm.encoding &= ~(PE_BYTESWAP|PE_ULAW);
  106.   if (dpm.encoding & PE_16BIT) 
  107.     dpm.encoding |= PE_SIGNED;
  108.   else 
  109.     dpm.encoding &= ~PE_SIGNED;
  110.  
  111.   if (dpm.name && dpm.name[0]=='-' && dpm.name[1]=='\0')
  112.     dpm.fd=1; /* data to stdout */
  113.   else
  114.     {
  115.       /* Open the audio file */
  116.       dpm.fd=open(dpm.name, OPEN_MODE, 0644);
  117.       if (dpm.fd<0)
  118.     {
  119.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
  120.            dpm.name, sys_errlist[errno]);
  121.       return -1;
  122.     }
  123.     }
  124.  
  125.   /* Generate a (rather non-standard) RIFF header. We don't know yet
  126.      what the block lengths will be. We'll fix that at close if this
  127.      is a seekable file. */
  128.  
  129.   memcpy(RIFFheader, orig_RIFFheader, 44);
  130.   
  131.   if (!(dpm.encoding & PE_MONO)) RIFFheader[22]='\002';
  132.  
  133.   *((int *)(RIFFheader+24))=LE_LONG(dpm.rate);
  134.  
  135.   t=dpm.rate; 
  136.   if (!(dpm.encoding & PE_MONO)) t*=2;
  137.   if (dpm.encoding & PE_16BIT) t*=2;
  138.   *((int *)(RIFFheader+28))=LE_LONG(t);
  139.  
  140.   if ((dpm.encoding & (PE_MONO | PE_16BIT)) == PE_MONO)
  141.     RIFFheader[32]='\001';
  142.   else if (!(dpm.encoding & PE_MONO) || (dpm.encoding & PE_16BIT))
  143.     RIFFheader[32]='\002';
  144.  
  145.   if (!(dpm.encoding & PE_16BIT)) RIFFheader[34]='\010';
  146.  
  147.   write(dpm.fd, RIFFheader, 44);
  148.  
  149.   /* Reset the length counter */
  150.   bytes_output=0;
  151.  
  152.   return 0;
  153. }
  154.  
  155. static void output_data(int32 *buf, int32 count)
  156. {
  157.   if (!(dpm.encoding & PE_MONO)) count*=2; /* Stereo samples */
  158.   
  159.   if (dpm.encoding & PE_16BIT)
  160.     {
  161.       s32tos16l(buf, count); /* Little-endian data */
  162.  
  163.       while ((-1==write(dpm.fd, buf, count * 2)) && errno==EINTR)
  164.     ;
  165.       bytes_output += count*2;
  166.     }
  167.   else
  168.     {
  169.       s32tou8(buf, count);
  170.       
  171.       while ((-1==write(dpm.fd, buf, count)) && errno==EINTR)
  172.     ;
  173.       bytes_output += count;
  174.     }
  175. }
  176.  
  177. static void close_output(void)
  178. {
  179.   if (dpm.fd != 1) /* We don't close stdout */
  180.     {
  181.       /* It's not stdout, so it's probably a file, and we can try
  182.          fixing the block lengths in the header before closing. */
  183.       if (lseek(dpm.fd, 4, SEEK_SET)>=0)
  184.     {
  185.       int32 tmp;
  186.       tmp=LE_LONG(bytes_output + 44 - 8);
  187.       write(dpm.fd, &tmp, 4);
  188.       lseek(dpm.fd, 40, SEEK_SET);
  189.       tmp=LE_LONG(bytes_output);
  190.       write(dpm.fd, &tmp, 4);
  191.     }
  192.       close(dpm.fd);
  193.     }
  194. }
  195.  
  196. /* Dummies */
  197. static void flush_output(void) { }
  198. static void purge_output(void) { }
  199.